//***************************************************************************
//   Copyright(c)2020, Xidian University D405.
//           All rights reserved
//
//   File name       :   axi_master_interface_wrapper.v
//   Module name     :   axi_master_interface_wrapper
//   Author          :   Zhao Yuchen
//   Date            :   2022/06/24
//   Version         :   v0.90
//   Edited by       :   Zhao Yuchen
// --------------------------------------------------------------------------
// Changelog : 
//   Version 0.00      Date(2022/02/26)
//   Abstract : AXI master interface with outstanding(multiple transaction)support.
//   Version 0.20      Date(2022/03/09)
//   Abstract : Add unalign address and unalign data write&read support.
//   Version 0.30      Date(2022/03/13)
//   Abstract : Parameterize the internal signal width, change the data width from 256 to 128(to fit dmac).
//   Version 0.31      Date(2022/03/14)
//   Abstract : Supplementary comments and code headers.
//   Version 0.40      Date(2022/03/15)
//   Abstract : Change write_fifo\read_fifo to wdata_fifo\rdata_fifo. Add wdesc(no need fifo) and rdesc_fifo.
//   Version 0.50      Data(2022/03/17)
//   Abstract : Add write\read done pulse signals. Add write read data done interrupt interface.
//   Version 0.60      Data(2022/03/22)
//   Abstract : Move the RxFIFO and TxFIFO out. Reduced clock cycle of FSM.
//   Version 0.70      Data(2022/03/23)
//   Abstract : Add TxFIFO(to AXI-Stream).
//   Version 0.80      Data(2022/03/28)
//   Abstract : Change the TxFIFO length fifo write enable after AXI master read data done, this can advoid TxFIFO's empty in the middle of a transaction.
//   Version 0.90      Data(2022/03/30)
//   Abstract : Add write back descriptors fifo.
//   Version 0.91      Data(2022/04/06)
//   Abstract : Separate Rx/Tx descriptors fifo, add write/read almost done flags. Update internal structure of AXI interface.
//   Version 0.92      Data(2022/04/12)
//   Abstract : 10G/40G TxFIFO MUX, fix almost_done problems.
//   Version 0.93      Data(2022/05/17)
//   Abstract : Fix AXI write FSM. Change write_data_ready_o to fit DMA.
//   Version 0.95      Data(2022/06/24)
//   Abstract : Enlarge CACHE of AXI write channel, fixed the usuall pulling down of wvalid caused by "read fifo slow" and "cache too small".
//---------------------------------------------------------------------------
// Interface list :
//                AXI Master
//                FIFO Control
//***************************************************************************
	module axi_master_interface_wrapper #
	(
	    //parameter integer DMA_DESC_LENG        = 16,
		// Parameters of Axi Master Bus Interface M_AXI
        // Burst Length. Supports 1, 2, 4, 8, 16, 32, 64, 128, 256 burst lengths
        //parameter integer AXI_UNALIGN_ADDR_EN  = 0,
        parameter integer AXI_BURST_LEN        = 256,
        parameter integer AXI_ID_WIDTH         = 6,
        parameter integer AXI_ADDR_WIDTH       = 40,
        parameter integer AXI_DATA_WIDTH       = 128,
        parameter integer AXI_LIB_WIDTH        = 13, //Width of Max Transmit Length(in BYTES)
        parameter integer AXI_AWUSER_WIDTH     = 0,
        parameter integer AXI_ARUSER_WIDTH     = 0,
        parameter integer AXI_WUSER_WIDTH      = 0,
        parameter integer AXI_RUSER_WIDTH      = 0,
        parameter integer AXI_BUSER_WIDTH      = 0,
        parameter integer AXI_MAX_INSTR_NUM    = 32 //Max transaction instructions number
	)
	(
		// Ports of Axi Master Bus Interface M_AXI
		input wire                           m_axi_aclk_i,
		input wire                           m_axi_aresetn_i,
		output wire [AXI_ID_WIDTH-1 : 0]     m_axi_awid_o,
		output wire [AXI_ADDR_WIDTH-1 : 0]   m_axi_awaddr_o,
		output wire [7 : 0]                  m_axi_awlen_o,
		output wire [2 : 0]                  m_axi_awsize_o,
		output wire [1 : 0]                  m_axi_awburst_o,
		output wire                          m_axi_awlock_o,
		output wire [3 : 0]                  m_axi_awcache_o,
		output wire [2 : 0]                  m_axi_awprot_o,
		output wire [3 : 0]                  m_axi_awqos_o,
		output wire [AXI_AWUSER_WIDTH-1 : 0] m_axi_awuser_o,
		output wire                          m_axi_awvalid_o,
		input wire                           m_axi_awready_i,
		output wire [AXI_DATA_WIDTH-1 : 0]   m_axi_wdata_o,
		output wire [AXI_DATA_WIDTH/8-1 : 0] m_axi_wstrb_o,
		output wire                          m_axi_wlast_o,
		output wire [AXI_WUSER_WIDTH-1 : 0]  m_axi_wuser_o,
		output wire                          m_axi_wvalid_o,
		input wire                           m_axi_wready_i,
		input wire  [AXI_ID_WIDTH-1 : 0]     m_axi_bid_i,
		input wire  [1 : 0]                  m_axi_bresp_i,
		input wire  [AXI_BUSER_WIDTH-1 : 0]  m_axi_buser_i,
		input wire                           m_axi_bvalid_i,
		output wire                          m_axi_bready_o,
		output wire [AXI_ID_WIDTH-1 : 0]     m_axi_arid_o,
		output wire [AXI_ADDR_WIDTH-1 : 0]   m_axi_araddr_o,
		output wire [7 : 0]                  m_axi_arlen_o,
		output wire [2 : 0]                  m_axi_arsize_o,
		output wire [1 : 0]                  m_axi_arburst_o,
		output wire                          m_axi_arlock_o,
		output wire [3 : 0]                  m_axi_arcache_o,
		output wire [2 : 0]                  m_axi_arprot_o,
		output wire [3 : 0]                  m_axi_arqos_o,
		output wire [AXI_ARUSER_WIDTH-1 : 0] m_axi_aruser_o,
		output wire                          m_axi_arvalid_o,
		input wire                           m_axi_arready_i,
		input wire  [AXI_ID_WIDTH-1 : 0]     m_axi_rid_i,
		input wire  [AXI_DATA_WIDTH-1 : 0]   m_axi_rdata_i,
		input wire  [1 : 0]                  m_axi_rresp_i,
		input wire                           m_axi_rlast_i,
		input wire  [AXI_RUSER_WIDTH-1 : 0]  m_axi_ruser_i,
		input wire                           m_axi_rvalid_i,
		output wire                          m_axi_rready_o,
		
		//******  [External Ports] Wirte Channel  ******//
		//Write Command Input
		input  wire [AXI_ID_WIDTH-1 : 0]     write_id_i,            //write transaction id input                                                   
        input  wire [AXI_ADDR_WIDTH-1 : 0]   write_addr_i,          //write transaction address input                                              
        input  wire [AXI_LIB_WIDTH-1 : 0]    write_len_in_byte_i,   //write transaction length(in byte) input                                      
        input  wire                          write_desc_en_i,       //write descriptor enable    
        input  wire                          write_desc_type_i,     //0: rxdesc   1:txdesc                                           
        output wire                          write_data_ready_o,    //master receive write data command ready      
        output wire                          write_desc_ready_o,    //master receive write descriptor command ready                            
        input  wire                          start_write_i,         //start a write transaction(input a write command) use posedge or a pulse input
        
        //Write Data FIFO Control Signals        
        output wire                          rxfifo_data_rd_en_o,
        input  wire [AXI_DATA_WIDTH-1 : 0]   rxfifo_data_dout_i,
        input  wire                          rxfifo_data_valid_i,
        input  wire                          rxfifo_empty_i,
        
        output wire                          axiw_rxdesc_fifo_rd_en_o,
        input  wire [AXI_DATA_WIDTH-1 : 0]   axiw_rxdesc_fifo_dout_i,
        input  wire                          axiw_rxdesc_fifo_empty_i,
        
        output wire                          axiw_txdesc_fifo_rd_en_o,
        input  wire [AXI_DATA_WIDTH-1 : 0]   axiw_txdesc_fifo_dout_i,
        input  wire                          axiw_txdesc_fifo_empty_i,
        
        
        //******  [External Ports] Read Channel    ******//
        input  wire [AXI_ID_WIDTH-1 : 0]     read_id_i,            //read transaction id
        input  wire [AXI_ADDR_WIDTH-1 : 0]   read_addr_i,          //read transaction address input
        input  wire [AXI_LIB_WIDTH-1 : 0]    read_len_in_byte_i,   //read transaction length in byte input
        input  wire                          read_desc_en_i,       //read descriptor enable
        input  wire                          read_desc_type_i,     //0: rxdesc   1:txdesc
        input  wire                          read_data_10g40g_sel_i, //0:10g    1:40g
        output wire                          read_ready_o,         //master receive read command ready 
        input  wire                          start_read_i,         //use a posedge to start a read transaction
        //Read Data FIFO Control Signals  
        output wire                          txfifo_data_wr_en_40g_o,
        output wire [AXI_DATA_WIDTH-1 : 0]   txfifo_data_din_40g_o,
        input  wire                          txfifo_full_40g_i,
        output wire                          txfifo_leng_wr_en_40g_o,
        output wire [AXI_LIB_WIDTH-1 : 0]    txfifo_leng_din_40g_o,
        output wire                          txfifo_start_40g_o,
        
        output wire                          txfifo_data_wr_en_10g_o,
        output wire [AXI_DATA_WIDTH-1 : 0]   txfifo_data_din_10g_o,
        input  wire                          txfifo_full_10g_i,
        output wire                          txfifo_leng_wr_en_10g_o,
        output wire [AXI_LIB_WIDTH-1 : 0]    txfifo_leng_din_10g_o,
        output wire                          txfifo_start_10g_o,
        
        output wire                          axir_rxdesc_fifo_wr_en_o,
        output wire [AXI_DATA_WIDTH-1 : 0]   axir_rxdesc_fifo_din_o,
        input  wire                          axir_rxdesc_fifo_full_i,
        output wire                          axir_txdesc_fifo_wr_en_o,
        output wire [AXI_DATA_WIDTH-1 : 0]   axir_txdesc_fifo_din_o,
        input  wire                          axir_txdesc_fifo_full_i,
        
        output wire [7 : 0]                  transaction_done_pulse_o, 
	// {read_desc_almost_done, write_desc_almost_done, read_data_almost_done, write_data_almost_done, read_desc_done, write_desc_done, read_data_done, write_data_done};
        output wire [2 : 0]                  debug_state_o,             //00:idle  01:writing  10:reading 11:w&r
  			input  wire [9 : 0]                  ram_2p_cfg_register,
  			input  wire [6 : 0]                  rf_2p_cfg_register
	);
	
	wire [AXI_LIB_WIDTH-1 : 0]   write_len_in_byte;
	wire [AXI_LIB_WIDTH-1 : 0]   read_len_in_byte;
	
	wire                         axiw_fifo_rd_en       ;
    wire [AXI_DATA_WIDTH-1 : 0]  axiw_fifo_rd_data     ;
    wire                         axiw_fifo_rd_valid    ;
    wire                         axiw_fifo_rd_empty    ;
    wire [1 : 0]                 axiw_data_or_desc_sel ;
    wire [1 : 0]                 axiw_desc_fifo_sel    ;
                                                    
    wire                         axir_fifo_wr_en       ;
    wire [AXI_DATA_WIDTH-1 : 0]  axir_fifo_wr_data     ;
    wire                         axir_fifo_wr_full     ;
    wire [1 : 0]                 axir_data_or_desc_sel ;
    wire [1 : 0]                 axir_desc_fifo_sel    ;
    wire [1 : 0]                 axir_txfifo_10g40g_sel;
    
    wire                         write_ready;

    assign write_len_in_byte  = (write_len_in_byte_i != 'd0) ? (write_len_in_byte_i - 'd1) : 'd0;
    assign read_len_in_byte   = (read_len_in_byte_i != 'd0) ? (read_len_in_byte_i - 'd1) : 'd0;
    //assign write_data_ready_o = write_ready & ~rxfifo_empty_i;    
    assign write_data_ready_o = write_ready;  
	assign write_desc_ready_o = write_ready;
    
    assign txfifo_leng_wr_en_40g_o   = ({read_data_10g40g_sel_i, read_desc_en_i} == 2'b10) ? start_read_i : 1'b0;
    assign txfifo_leng_din_40g_o     = ({read_data_10g40g_sel_i, read_desc_en_i} == 2'b10) ? read_len_in_byte_i : 'd0;
    assign txfifo_leng_wr_en_10g_o   = ({read_data_10g40g_sel_i, read_desc_en_i} == 2'b00) ? start_read_i : 1'b0;
    assign txfifo_leng_din_10g_o     = ({read_data_10g40g_sel_i, read_desc_en_i} == 2'b00) ? read_len_in_byte_i : 'd0;
    
    assign txfifo_start_40g_o        = (axir_txfifo_10g40g_sel == 2'b10) ? (transaction_done_pulse_o[1]) : 'b0;
    assign txfifo_start_10g_o        = (axir_txfifo_10g40g_sel == 2'b01) ? (transaction_done_pulse_o[1]) : 'b0;
    
    // Instantiation of Axi Bus Interface M_AXI
	axi_master_with_outstanding #
	( 
	    //.AXI_UNALIGN_ADDR_EN     (AXI_UNALIGN_ADDR_EN),
		.AXI_BURST_LEN               (AXI_BURST_LEN),
		.AXI_ID_WIDTH                (AXI_ID_WIDTH),
		.AXI_ADDR_WIDTH              (AXI_ADDR_WIDTH),
		.AXI_DATA_WIDTH              (AXI_DATA_WIDTH),
		.AXI_LIB_WIDTH               (AXI_LIB_WIDTH),
		.AXI_AWUSER_WIDTH            (AXI_AWUSER_WIDTH),
		.AXI_ARUSER_WIDTH            (AXI_ARUSER_WIDTH),
		.AXI_WUSER_WIDTH             (AXI_WUSER_WIDTH),
		.AXI_RUSER_WIDTH             (AXI_RUSER_WIDTH),
		.AXI_BUSER_WIDTH             (AXI_BUSER_WIDTH),
		.AXI_MAX_INSTR_NUM           (AXI_MAX_INSTR_NUM)
	) 
	axi_master
	(
		.M_AXI_ACLK_I                (m_axi_aclk_i),
		.M_AXI_ARESETN_I             (m_axi_aresetn_i),
		.M_AXI_AWID_O                (m_axi_awid_o),
		.M_AXI_AWADDR_O              (m_axi_awaddr_o),
		.M_AXI_AWLEN_O               (m_axi_awlen_o),
		.M_AXI_AWSIZE_O              (m_axi_awsize_o),
		.M_AXI_AWBURST_O             (m_axi_awburst_o),
		.M_AXI_AWLOCK_O              (m_axi_awlock_o),
		.M_AXI_AWCACHE_O             (m_axi_awcache_o),
		.M_AXI_AWPROT_O              (m_axi_awprot_o),
		.M_AXI_AWQOS_O               (m_axi_awqos_o),
		.M_AXI_AWUSER_O              (m_axi_awuser_o),
		.M_AXI_AWVALID_O             (m_axi_awvalid_o),
		.M_AXI_AWREADY_I             (m_axi_awready_i),
		.M_AXI_WDATA_O               (m_axi_wdata_o),
		.M_AXI_WSTRB_O               (m_axi_wstrb_o),
		.M_AXI_WLAST_O               (m_axi_wlast_o),
		.M_AXI_WUSER_O               (m_axi_wuser_o),
		.M_AXI_WVALID_O              (m_axi_wvalid_o),
		.M_AXI_WREADY_I              (m_axi_wready_i),
		.M_AXI_BID_I                 (m_axi_bid_i),
		.M_AXI_BRESP_I               (m_axi_bresp_i),
		.M_AXI_BUSER_I               (m_axi_buser_i),
		.M_AXI_BVALID_I              (m_axi_bvalid_i),
		.M_AXI_BREADY_O              (m_axi_bready_o),
		.M_AXI_ARID_O                (m_axi_arid_o),
		.M_AXI_ARADDR_O              (m_axi_araddr_o),
		.M_AXI_ARLEN_O               (m_axi_arlen_o),
		.M_AXI_ARSIZE_O              (m_axi_arsize_o),
		.M_AXI_ARBURST_O             (m_axi_arburst_o),
		.M_AXI_ARLOCK_O              (m_axi_arlock_o),
		.M_AXI_ARCACHE_O             (m_axi_arcache_o),
		.M_AXI_ARPROT_O              (m_axi_arprot_o),
		.M_AXI_ARQOS_O               (m_axi_arqos_o),
		.M_AXI_ARUSER_O              (m_axi_aruser_o),
		.M_AXI_ARVALID_O             (m_axi_arvalid_o),
		.M_AXI_ARREADY_I             (m_axi_arready_i),
		.M_AXI_RID_I                 (m_axi_rid_i),
		.M_AXI_RDATA_I               (m_axi_rdata_i),
		.M_AXI_RRESP_I               (m_axi_rresp_i),
		.M_AXI_RLAST_I               (m_axi_rlast_i),
		.M_AXI_RUSER_I               (m_axi_ruser_i),
		.M_AXI_RVALID_I              (m_axi_rvalid_i),
		.M_AXI_RREADY_O              (m_axi_rready_o),
		
		.write_id_i                  (write_id_i),
		.write_addr_i                (write_addr_i),
		.write_len_in_byte_i         (write_len_in_byte),
		.write_desc_en_i             (write_desc_en_i),
		.write_desc_type_i           (write_desc_type_i),
		.write_data_i                (axiw_fifo_rd_data),
		.start_write_i               (start_write_i),
		.write_ready_o               (write_ready),
		
		.write_fifo_rd_en_o          (axiw_fifo_rd_en),
		.write_fifo_rd_empty_i       (axiw_fifo_rd_empty),
		.write_fifo_rd_valid_i       (axiw_fifo_rd_valid),
		
		.write_data_or_desc_sel_o    (axiw_data_or_desc_sel),
		.write_desc_fifo_sel_o       (axiw_desc_fifo_sel),
		
		.read_id_i                   (read_id_i),
		.read_addr_i                 (read_addr_i),
		.read_len_in_byte_i          (read_len_in_byte),
		.read_desc_en_i              (read_desc_en_i),
		.read_desc_type_i            (read_desc_type_i),
		.read_data_10g40g_sel_i      (read_data_10g40g_sel_i),
		.read_data_o                 (axir_fifo_wr_data),
		.start_read_i                (start_read_i),
		.read_ready_o                (read_ready_o),
		
		//ports are used to write txfifo(datafifo) OR descfifo
		.read_fifo_wr_en_o           (axir_fifo_wr_en), 
		.read_fifo_wr_full_i         (axir_fifo_wr_full),
		
		.read_data_txfifo_sel_o      (axir_txfifo_10g40g_sel),
		.read_data_or_desc_sel_o     (axir_data_or_desc_sel),
		.read_desc_fifo_sel_o        (axir_desc_fifo_sel),
		
		.transaction_done_pulse_o    (transaction_done_pulse_o),
	 	.debug_state_o               (debug_state_o),
		.ram_2p_cfg_register					(ram_2p_cfg_register),
		.rf_2p_cfg_register						(rf_2p_cfg_register)
	);
	
	axi_fifo_mux #
	(
	   .AXI_DATA_WIDTH              (AXI_DATA_WIDTH),
	   .AXI_LIB_WIDTH               (AXI_LIB_WIDTH)
	)
	axi_fifo_mux_inst
	(
	   //***** AXI FIFO Control *****//
	   .axiw_fifo_rd_en_i                 (axiw_fifo_rd_en       ),
	   .axiw_fifo_rd_data_o               (axiw_fifo_rd_data     ),
	   .axiw_fifo_rd_empty_o              (axiw_fifo_rd_empty    ),
	   .axiw_fifo_rd_valid_o              (axiw_fifo_rd_valid    ),
	   .axiw_data_or_desc_sel_i           (axiw_data_or_desc_sel ),
	   .axiw_desc_fifo_sel_i              (axiw_desc_fifo_sel    ),
	   
	   .axir_fifo_wr_en_i                 (axir_fifo_wr_en       ),
	   .axir_fifo_wr_data_i               (axir_fifo_wr_data     ),
	   .axir_fifo_wr_full_o               (axir_fifo_wr_full     ),
	   .axir_data_or_desc_sel_i           (axir_data_or_desc_sel ),
	   .axir_desc_fifo_sel_i              (axir_desc_fifo_sel    ),
	   .axir_txfifo_10g40g_sel_i          (axir_txfifo_10g40g_sel),
	   //***** RxFIFO *****//   
	   .rxfifo_data_rd_en_o               (rxfifo_data_rd_en_o     ),
	   .rxfifo_data_dout_i                (rxfifo_data_dout_i      ),
	   .rxfifo_data_valid_i               (rxfifo_data_valid_i     ),
	   //.rxfifo_empty_i                    (rxfifo_empty_i          ),
	   //***** AXI Write RxDesc *****// 
	   .axiw_rxdesc_fifo_rd_en_o          (axiw_rxdesc_fifo_rd_en_o),
	   .axiw_rxdesc_fifo_dout_i           (axiw_rxdesc_fifo_dout_i ),
	   .axiw_rxdesc_fifo_empty_i          (axiw_rxdesc_fifo_empty_i),
	   //***** AXI Write TxDesc *****//
	   .axiw_txdesc_fifo_rd_en_o          (axiw_txdesc_fifo_rd_en_o),
	   .axiw_txdesc_fifo_dout_i           (axiw_txdesc_fifo_dout_i ),
	   .axiw_txdesc_fifo_empty_i          (axiw_txdesc_fifo_empty_i),
	   //***** TxFIFO 40G *****//     
	   .txfifo_data_wr_en_40g_o           (txfifo_data_wr_en_40g_o ),
	   .txfifo_data_din_40g_o             (txfifo_data_din_40g_o   ),
	   .txfifo_full_40g_i                 (txfifo_full_40g_i       ),
	   //***** TxFIFO 10G *****// 
	   .txfifo_data_wr_en_10g_o           (txfifo_data_wr_en_10g_o ),
	   .txfifo_data_din_10g_o             (txfifo_data_din_10g_o   ),
	   .txfifo_full_10g_i                 (txfifo_full_10g_i       ),
	   //***** AXI Read RxDesc *****//
	   .axir_rxdesc_fifo_wr_en_o          (axir_rxdesc_fifo_wr_en_o),
	   .axir_rxdesc_fifo_din_o            (axir_rxdesc_fifo_din_o  ),
	   .axir_rxdesc_fifo_full_i           (axir_rxdesc_fifo_full_i ),
	   //***** AXI Read TxDesc *****//
	   .axir_txdesc_fifo_wr_en_o          (axir_txdesc_fifo_wr_en_o),
	   .axir_txdesc_fifo_din_o            (axir_txdesc_fifo_din_o  ),
	   .axir_txdesc_fifo_full_i           (axir_txdesc_fifo_full_i )
	);
	
	
	endmodule
